package com.yunhe.abnormal.repository.base.impl;

import com.yunhe.common.model.data.AbnormalRuleFormulaObject;
import com.yunhe.abnormal.repository.base.AbnormalRuleFormulaObjectRepository;
import org.neo4j.ogm.model.Result;
import org.neo4j.ogm.session.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.*;

@Repository
public class AbnormalRuleFormulaObjectRepositoryImpl implements AbnormalRuleFormulaObjectRepository {
    @Autowired
    private Session session;

    private List<AbnormalRuleFormulaObject> getObjectList(Result results) {
        List<AbnormalRuleFormulaObject> resultList = new ArrayList<>();
        for (Map<String, Object> result : results) {
            AbnormalRuleFormulaObject object = new AbnormalRuleFormulaObject();
            object.setAbnormalRuleId((Long) result.get("abnormalRuleId"));
            object.setAlarmLevelId((Long) result.get("alarmLevelId"));
            object.setFormula((String) result.get("formula"));
            object.setDescription((String) result.get("description"));
//            object.setPointNumber((Long) result.get("pointNumber"));
            object.setMeasPointNumbers(castList(result.get("measPointNumbers"), Long.class));
            object.setRelatedPointNumbers(castList(result.get("relatedPointNumbers"), Long.class));
            resultList.add(object);
        }
        return resultList;
    }

    private List<Long> getLongList(Result results) {
        List<Long> resultList = new ArrayList<>();
        for (Map<String, Object> result : results) {
            if (result.get("measPointNumbers") != null) {
                resultList.addAll(castList(result.get("measPointNumbers"), Long.class));
            }
        }
        HashSet set = new HashSet(resultList);
        resultList.clear();
        resultList.addAll(set);
        return resultList;
    }

    @Override
    public List<AbnormalRuleFormulaObject> findByMeasPointNumber(String pointNumber) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("measPointNumber", pointNumber);
        String cypher = "match (ar:AbnormalRule)-[r:ALARM_LEVEL_OF]->(al:AlarmLevel) where r.measPointNumberStr contains {measPointNumber} " +
                "return ID(ar) as abnormalRuleId, ID(al) as alarmLevelId, r.formula as formula, r.description as description, " +
                "r.pointNumber as pointNumber, r.measPointNumbers as measPointNumbers, r.relatedPointNumbers as relatedPointNumbers";
        Result result = session.query(cypher, paramMap);
        return getObjectList(result);
    }

    @Override
    public List<Long> getMeasPointNumbersByRuleId(Long id) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("id", id);
        String cypher = "match (ar:AbnormalRule)-[r:ALARM_LEVEL_OF]->(al:AlarmLevel) where ID(ar) = {id} " +
                "return r.measPointNumbers as measPointNumbers";
        Result results = session.query(cypher, paramMap);
        List<Long> list = new ArrayList<>();
        for (Map<String, Object> result : results) {
            list.addAll(castList(result.get("measPointNumbers"), Long.class));
        }
        return list;
    }

    /**
     * 获取全部告警规则点号
     * @return
     */
    @Override
    public List<Long> getAllMeasPointNumber() {
        Map<String, Object> paramMap = new HashMap<>();
        String cypher = "match (ar:AbnormalRule)-[r:ALARM_LEVEL_OF]->(al:AlarmLevel) return distinct r.measPointNumbers as measPointNumbers";
        Result result = session.query(cypher, paramMap);
        return getLongList(result);
    }

    /**
     * 根据告警规则ID获取相关的量测点号
     * @param ruleId
     * @return
     */
    @Override
    public List<AbnormalRuleFormulaObject> findByRuleId(Long ruleId) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("ruleId", ruleId);
        String cypher = "match (ar:AbnormalRule)-[r:ALARM_LEVEL_OF]->(al:AlarmLevel) where ID(ar) = {ruleId} " +
                "return ID(ar) as abnormalRuleId, ID(al) as alarmLevelId, r.formula as formula, r.description as description, " +
                "r.pointNumber as pointNumber, r.measPointNumbers as measPointNumbers, r.relatedPointNumbers as relatedPointNumbers";
        Result result = session.query(cypher, paramMap);
        return getObjectList(result);
    }

    @Override
    public List<AbnormalRuleFormulaObject> findAllAbnormalRuleFormulaObject() {
        Map<String, Object> paramMap = new HashMap<>();
        String cypher = "match (ar:AbnormalRule)-[r:ALARM_LEVEL_OF]->(al:AlarmLevel) " +
                "return ID(ar) as abnormalRuleId, ID(al) as alarmLevelId, r.formula as formula, r.description as description, " +
                "r.pointNumber as pointNumber, r.measPointNumbers as measPointNumbers, r.relatedPointNumbers as relatedPointNumbers";
        Result result = session.query(cypher, paramMap);
        return getObjectList(result);
    }
  
    @Override
    public AbnormalRuleFormulaObject findByRuleIdAndLevelId(Long ruleId, Long levelId) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("ruleId", ruleId);
        paramMap.put("levelId", levelId);
        String cypher = "match (ar:AbnormalRule)-[r:ALARM_LEVEL_OF]->(al:AlarmLevel) where ID(ar) = {ruleId} and ID(al) = {levelId} " +
                "return ID(ar) as abnormalRuleId, ID(al) as alarmLevelId, r.formula as formula, r.description as description, " +
                "r.pointNumber as pointNumber, r.measPointNumbers as measPointNumbers, r.relatedPointNumbers as relatedPointNumbers";
        Result result = session.query(cypher, paramMap);
        List<AbnormalRuleFormulaObject> formulaObjects = getObjectList(result);
        if (formulaObjects != null && !formulaObjects.isEmpty()) {
            return getObjectList(result).get(0);
        }
        return null;
    }

    public static <T> List<T> castList(Object obj, Class<T> clazz) {
        List<T> result = new ArrayList<T>();
        if (obj instanceof ArrayList) {
            for (Object o :  (List<?>) obj) {
                result.add(clazz.cast(o));
            }
            return result;
        } else if (obj instanceof Long[]) {
            Long[] list = (Long[]) obj;
            for (int idx = 0; idx < list.length; idx++) {
                result.add(clazz.cast(list[idx]));
            }
            return result;
        }
        return null;

    }

}
